import { BleManager, Characteristic, Device, Subscription } from 'react-native-ble-plx';

type BluetoothState = 'PoweredOn' | 'PoweredOff' | 'Resetting' | 'Unauthorized' | 'Unknown' | 'Unsupported';

class BluetoothService {
    private static instance: BluetoothService;
    private manager: BleManager;
    private device: Device | null = null;
    private stateListeners: Subscription[] = [];
    private notifySubscriptions: Record<string, Subscription> = {};
    private isInitialized: boolean = false;

    private constructor() {
        this.manager = new BleManager();
        this.isInitialized = true;
    }

    public static getInstance(): BluetoothService {
        if (!BluetoothService.instance) {
            BluetoothService.instance = new BluetoothService();
        }
        return BluetoothService.instance;
    }

    public isReady(): boolean {
        return this.isInitialized;
    }

    async connectDevice(
        deviceId: string,
        serviceUUIDs: string[],
        options: {
            autoConnect?: boolean;
            requestMTU?: number;
            connectionPriority?: number;
            shouldEnableNotificationWhenServiceDiscovered?: boolean;
        } = {}
    ): Promise<Device> {
        try {

            // 连接设备
            this.device = await this.manager.connectToDevice(deviceId, {
                autoConnect: options.autoConnect || false,
                timeout: 10000 // 增加连接超时时间到10秒
            });

            // 发现服务和特征
            console.log('正在发现服务和特征...');
            this.device = await this.device.discoverAllServicesAndCharacteristics();
            console.log(this.device)
            console.log('服务和特征发现完成');

            // 请求MTU (Android only)
            if (options.requestMTU) {
                try {
                    await this.device.requestMTU(options.requestMTU);
                    console.log(`MTU设置为: ${options.requestMTU}`);
                } catch (mtuError) {
                    console.warn('MTU请求失败:', mtuError);
                }
            }

            // 设置连接优先级 (Android only)
            if (options.connectionPriority) {
                try {
                    await this.manager.requestConnectionPriorityForDevice(
                        deviceId,
                        options.connectionPriority
                    );
                    console.log(`连接优先级设置为: ${options.connectionPriority}`);
                } catch (priorityError) {
                    console.warn('连接优先级修改失败:', priorityError);
                }
            }

            return this.device;
        } catch (error) {
            console.log(error)
            throw new Error('连接失败');
        }
    }

    addStateListener(callback: (state: BluetoothState) => void): Subscription {
        const subscription = this.manager.onStateChange((state) => {
            callback(state);
        }, true);
        this.stateListeners.push(subscription);
        return subscription;
    }

    async addNotifyRequest(
        serviceUUID: string,
        characteristicUUID: string,
        callback: (data: string) => void
    ): Promise<Subscription> {
        if (!this.device) {
            throw new Error('No device connected');
        }

        const subscription = this.device.monitorCharacteristicForService(
            serviceUUID,
            characteristicUUID,
            (error: Error | null, characteristic: Characteristic | null) => {
                if (error || !characteristic) {
                    // console.error('通知错误:', error);
                    return;
                }
                if (!characteristic.value) {
                    return;
                }
                // 解码 Base64 数据
                const decodedData = atob(characteristic.value); // Base64 解码
                // 将解码后的数据转换为 Uint8Array
                const uint8Array = new Uint8Array(decodedData.length);
                for (let i = 0; i < decodedData.length; i++) {
                    uint8Array[i] = decodedData.charCodeAt(i);
                }
                // 将 Uint8Array 转换为 hex 字符串
                const hexString = this.arrayBufferToHex(uint8Array.buffer);
                // 调用回调函数，传递解析后的数据
                callback(hexString);
            }
        );

        // 存储订阅
        this.notifySubscriptions[`${serviceUUID.toLowerCase()}-${characteristicUUID.toLowerCase()}`] = subscription;
        return subscription;
    }

    // 将 ArrayBuffer 转换为 hex 字符串
    arrayBufferToHex(buffer: ArrayBufferLike) {
        return Array.from(new Uint8Array(buffer))
            .map(byte => byte.toString(16).padStart(2, '0'))
            .join('');
    }

    removeAllNotifyRequests(): void {
        Object.values(this.notifySubscriptions).forEach(sub => sub.remove());
        this.notifySubscriptions = {};
        this.stateListeners.forEach(sub => sub.remove());
        this.stateListeners = [];
    }

    // 按服务与特征取消单个通知订阅
    removeNotifyRequest(serviceUUID: string, characteristicUUID: string): void {
        const key = `${serviceUUID.toLowerCase()}-${characteristicUUID.toLowerCase()}`;
        const sub = this.notifySubscriptions[key];
        if (sub) {
            try { sub.remove(); } catch (_) {}
            delete this.notifySubscriptions[key];
        }
    }

    hexStringToUint8Array(hexString: string) {
        const buffer = new ArrayBuffer(hexString.length / 2);
        const view = new Uint8Array(buffer);

        for (let i = 0; i < hexString.length; i += 2) {
            const byteStr = hexString.substr(i, 2);
            const byteValue = parseInt(byteStr, 16);
            view[i / 2] = byteValue;
        }

        return view;
    }

    // 将 Uint8Array 转换为 Base64
    uint8ArrayToBase64(uint8Array: Uint8Array) {
        let binary = '';
        for (let i = 0; i < uint8Array.length; i++) {
            binary += String.fromCharCode(uint8Array[i]);
        }
        return btoa(binary);
    }

    async writeCommand(
        serviceUUID: string,
        characteristicUUID: string,
        command: string,
        withResponse?: boolean | undefined
    ): Promise<void> {
        if (!this.device) {
            throw new Error('No device connected');
        }

        try {
            console.log(await this.device.characteristicsForService(serviceUUID))
            // 将 hex 命令转换为 Uint8Array
            const byteArray = this.hexStringToUint8Array(command);

            // 将 Uint8Array 转换为 Base64
            const base64Command = this.uint8ArrayToBase64(byteArray);

            if (withResponse) {
                await this.device.writeCharacteristicWithResponseForService(
                    serviceUUID.toLowerCase(),
                    characteristicUUID.toLowerCase(),
                    base64Command
                );
            } else {
                await this.device.writeCharacteristicWithoutResponseForService(
                    serviceUUID.toLowerCase(),
                    characteristicUUID.toLowerCase(),
                    base64Command
                );
            }

        } catch (error) {
            console.error('蓝牙写入失败:', error);
        }
    }

    async findDeviceByNamePrefix(serviceUUIDs: string[] | null, namePrefix: string | string[]): Promise<Device | null> {
        return new Promise((resolve) => {
            let foundDevice: Device | null = null;
            this.manager.startDeviceScan(serviceUUIDs, null, (error, device) => {
                if (error) {
                    console.error('Scan error:', error);
                    this.manager.stopDeviceScan();
                    resolve(null);
                    return;
                }
                if (typeof namePrefix === "string") {
                    if (device?.name?.startsWith(namePrefix)) {
                        foundDevice = device;
                        this.manager.stopDeviceScan();
                        resolve(device);
                    }
                } else {
                    if (namePrefix.some(prefix => device?.name?.startsWith(prefix))) {
                        foundDevice = device;
                        this.manager.stopDeviceScan();
                        resolve(device);
                    }
                }

            });
            // 设置5秒超时
            setTimeout(() => {
                this.manager.stopDeviceScan();
                resolve(foundDevice);
            }, 5000);
        });
    }

    async disconnectDevice() {
        try {
            if (this.device) {
                // 先取消所有通知订阅
                this.removeAllNotifyRequests();
                
                // 取消设备连接
                await this.manager.cancelDeviceConnection(this.device.id);
                
                // 重置设备引用
                this.device = null;
                
                console.log('设备已断开连接');
            }
        } catch (error) {
            console.error('断开设备连接时出错:', error);
            // 即使出错也要重置设备引用
            this.device = null;
        }
    }
}

export default BluetoothService.getInstance();
